home *** CD-ROM | disk | FTP | other *** search
- //: C25:ObservedFlower.cpp
- // From Thinking in C++, 2nd Edition
- // Available at http://www.BruceEckel.com
- // (c) Bruce Eckel 1999
- // Copyright notice in Copyright.txt
- // Demonstration of "observer" pattern
- #include "Observable.h"
- #include <iostream>
- #include <vector>
- #include <algorithm>
- #include <string>
- using namespace std;
-
- class Flower {
- bool isOpen;
- public:
- Flower() : isOpen(false),
- openNotifier(this), closeNotifier(this) {}
- void open() { // Opens its petals
- isOpen = true;
- openNotifier.notifyObservers();
- closeNotifier.open();
- }
- void close() { // Closes its petals
- isOpen = false;
- closeNotifier.notifyObservers();
- openNotifier.close();
- }
- // Using the "inner class" idiom:
- class OpenNotifier;
- friend class Flower::OpenNotifier;
- class OpenNotifier : public Observable {
- Flower* parent;
- bool alreadyOpen;
- public:
- OpenNotifier(Flower* f) : parent(f),
- alreadyOpen(false) {}
- void notifyObservers(Argument* arg=0) {
- if(parent->isOpen && !alreadyOpen) {
- setChanged();
- Observable::notifyObservers();
- alreadyOpen = true;
- }
- }
- void close() { alreadyOpen = false; }
- } openNotifier;
- class CloseNotifier;
- friend class Flower::CloseNotifier;
- class CloseNotifier : public Observable {
- Flower* parent;
- bool alreadyClosed;
- public:
- CloseNotifier(Flower* f) : parent(f),
- alreadyClosed(false) {}
- void notifyObservers(Argument* arg=0) {
- if(!parent->isOpen && !alreadyClosed) {
- setChanged();
- Observable::notifyObservers();
- alreadyClosed = true;
- }
- }
- void open() { alreadyClosed = false; }
- } closeNotifier;
- };
-
- class Bee {
- string name;
- // An "inner class" for observing openings:
- class OpenObserver;
- friend class Bee::OpenObserver;
- class OpenObserver : public Observer {
- Bee* parent;
- public:
- OpenObserver(Bee* b) : parent(b) {}
- void update(Observable*, Argument *) {
- cout << "Bee " << parent->name
- << "'s breakfast time!\n";
- }
- } openObsrv;
- // Another "inner class" for closings:
- class CloseObserver;
- friend class Bee::CloseObserver;
- class CloseObserver : public Observer {
- Bee* parent;
- public:
- CloseObserver(Bee* b) : parent(b) {}
- void update(Observable*, Argument *) {
- cout << "Bee " << parent->name
- << "'s bed time!\n";
- }
- } closeObsrv;
- public:
- Bee(string nm) : name(nm),
- openObsrv(this), closeObsrv(this) {}
- Observer& openObserver() { return openObsrv; }
- Observer& closeObserver() { return closeObsrv;}
- };
-
- class Hummingbird {
- string name;
- class OpenObserver;
- friend class Hummingbird::OpenObserver;
- class OpenObserver : public Observer {
- Hummingbird* parent;
- public:
- OpenObserver(Hummingbird* h) : parent(h) {}
- void update(Observable*, Argument *) {
- cout << "Hummingbird " << parent->name
- << "'s breakfast time!\n";
- }
- } openObsrv;
- class CloseObserver;
- friend class Hummingbird::CloseObserver;
- class CloseObserver : public Observer {
- Hummingbird* parent;
- public:
- CloseObserver(Hummingbird* h) : parent(h) {}
- void update(Observable*, Argument *) {
- cout << "Hummingbird " << parent->name
- << "'s bed time!\n";
- }
- } closeObsrv;
- public:
- Hummingbird(string nm) : name(nm),
- openObsrv(this), closeObsrv(this) {}
- Observer& openObserver() { return openObsrv; }
- Observer& closeObserver() { return closeObsrv;}
- };
-
- int main() {
- Flower f;
- Bee ba("A"), bb("B");
- Hummingbird ha("A"), hb("B");
- f.openNotifier.addObserver(ha.openObserver());
- f.openNotifier.addObserver(hb.openObserver());
- f.openNotifier.addObserver(ba.openObserver());
- f.openNotifier.addObserver(bb.openObserver());
- f.closeNotifier.addObserver(ha.closeObserver());
- f.closeNotifier.addObserver(hb.closeObserver());
- f.closeNotifier.addObserver(ba.closeObserver());
- f.closeNotifier.addObserver(bb.closeObserver());
- // Hummingbird B decides to sleep in:
- f.openNotifier.deleteObserver(hb.openObserver());
- // Something changes that interests observers:
- f.open();
- f.open(); // It's already open, no change.
- // Bee A doesn't want to go to bed:
- f.closeNotifier.deleteObserver(
- ba.closeObserver());
- f.close();
- f.close(); // It's already closed; no change
- f.openNotifier.deleteObservers();
- f.open();
- f.close();
- } ///:~
-